﻿namespace EyeSoft.Wpf.Facilities.Collection.Direct
{
	using System;
	using System.Collections.Generic;
	using System.Linq;

	using EyeSoft.Mapping;
	using EyeSoft.Wpf.Facilities.Collections.ObjectModel;

	internal class CollectionFilled<TService, TCollectionType> :
		ICollectionFilled<TCollectionType>
		where TService : IDisposable
	{
		private readonly LoaderParams<TService> loaderParams;

		private readonly Func<TService, IEnumerable<TCollectionType>> func;

		private readonly IMapper mapper;

		public CollectionFilled(
			LoaderParams<TService> loaderParams,
			Func<TService, IEnumerable<TCollectionType>> func)
		{
			this.loaderParams = loaderParams;
			this.func = func;
			mapper = loaderParams.Mapper;
		}

		public void Completed(Action<SmartObservableCollection<TCollectionType>> completed)
		{
			if (loaderParams.TaskFactory == null)
			{
				completed(LoadCollection());
				return;
			}

			loaderParams
				.TaskFactory
				.StartNew(() => LoadCollection())
				.ContinueWith(t => TaskContinue.Execute(() => completed(t.Result)));
		}

		public void Completed<TConverted>(Action<SmartObservableCollection<TConverted>> completed)
		{
			if (loaderParams.TaskFactory == null)
			{
				var collection = LoadCollection();

				var converted = ConvertCollection<TConverted>(collection);

				completed(converted);

				return;
			}

			loaderParams
				.TaskFactory
				.StartNew(() => ConvertCollection<TConverted>(LoadCollection()))
				.ContinueWith(t => TaskContinue.Execute(() => completed(t.Result)));
		}

		private SmartObservableCollection<TConverted>
			ConvertCollection<TConverted>(IEnumerable<TCollectionType> collection)
		{
			var itemsConverted = collection.Select(x => mapper.Map<TConverted>(x));

			var converted = new SmartObservableCollection<TConverted>(itemsConverted);

			return converted;
		}

		private SmartObservableCollection<TCollectionType> LoadCollection()
		{
			var collection = new SmartObservableCollection<TCollectionType>();

			var dataService =
				new DataService<TService>(
					loaderParams.Mapper,
					loaderParams.ProxyFactory);

			dataService.LoadEnumerable(func, collection);

			return collection;
		}
	}
}